<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./assets/global.css">

    <style>
        .game-container {
            display: flex;
        }

        .turtle-blind-box,
        .info-panel {
            position: relative;
            display: inline-flex;
            width: 400px;
            height: 400px;
        }

        .info-panel {
            flex-direction: column;
        }

        .info-panel .form {
            width: 100%;
            display: flex;
            flex-direction: column;
            border: 2px solid #666;
            border-left: 0;
            padding-bottom: 4px;
            box-sizing: border-box;
        }

        .info-panel .form-item {
            display: flex;
            padding-left: 40px;
        }

        .info-panel .form-item__label {
            width: 80px
        }

        .info-panel select {
            width: 80px;
            border-color: #666;
            outline: none;
        }

        .info-panel .start-btn {
            width: 80px;
            position: absolute;
            top: 8px;
            right: 40px;
            background-color: #3a77fc;
            height: 36px;
            display: flex;
            justify-content: center;
            align-items: center;
            color: #fff;
            cursor: pointer;
            user-select: none;
        }

        .info-panel .start-btn:active {
            opacity: .6;
        }

        .info-panel .history {
            width: 100%;
            display: flex;
            flex-direction: column;
            border: 2px solid #666;
            height: calc(100% - 48px);
            box-sizing: border-box;
            border-left: 0;
            border-top: 0;
            overflow-y: auto;
        }

        .info-panel .history-item {
            display: flex;
            flex-direction: column;
            border-bottom: 1px solid #666;
        }

        .info-panel .history-item .base-info {
            display: flex;
            justify-content: space-between;
            padding: 10px;
        }

        .info-panel .turtle-info {
            display: flex;
            flex-wrap: wrap;
            padding: 10px;
        }

        .info-panel .turtle-info img {
            width: 20px;
        }

        .info-panel .turtle-item {
            display: flex;
            align-items: center;
            justify-content: center;
            margin-right: 10px;
        }

        .turtle-grid {
            position: absolute;
            width: 100%;
            height: 100%;
            display: grid;
            border-left: 2px solid #666;
            border-top: 2px solid #666;
            grid-template-columns: repeat(3, calc(100% / 3));
            grid-template-rows: repeat(3, calc(100% / 3));
            box-sizing: border-box;
        }

        .turtle-grid-item {
            border-right: 2px solid #666;
            border-bottom: 2px solid #666;
            counter-increment: item-counter;
            box-sizing: border-box;
            position: relative;
        }

        .turtle-grid-item img {
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            z-index: 1;
        }

        .turtle-grid-item::after {
            position: absolute;
            top: 0;
            left: 0;
            z-index: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            width: 100%;
            height: 100%;
            color: #000;
            font-size: 40px;
            content: counter(item-counter);
        }

        #special-effects {
            width: 100%;
            height: 100%;
            position: absolute;
            z-index: 10;
        }


        .text-effects {
            position: absolute;
            display: flex;
            flex-direction: column;
            width: 6em;
            bottom: 20px;
            z-index: 15;
            right: 0;
            opacity: 0;
        }

        .text-effects.show {
            right: 20px;
            opacity: 1;
            transition: all .5s ease-out;
        }

        .text-effects-title {
            color: rgba(255, 50, 50, 1);
            text-shadow: 1px 1px rgba(200, 200, 200, 1);
            font-size: 30px;
            text-align: right;
        }

        .text-effects-subtitle {
            color: rgba(255, 50, 50, 1);
            text-shadow: 1px 1px rgba(200, 200, 200, 1);
            font-size: 20px;
            text-align: right;
        }
    </style>
</head>

<body>
    <!-- 
        规则    

        共有10种颜色的乌龟，出现概率均等（各占总数的1/10），每次完全随机抽取，“买家”可以“许愿”一种幸运颜色，初始指定乌龟总数，依次放入1-9号格，放满后开始结算。
        触发幸运色：每拆出1只幸运色乌龟，立刻加赠1只；
        对对碰：2个同色格，一起拿走，加赠1只； ✔
        三连位：同一直线上（横、竖、对角线）3个同色格，一起拿走，加赠3只； ✔
        清台: +5
    -->
    <div class="game-container">
        <div class="turtle-blind-box">
            <div class="turtle-grid">
                <div class="turtle-grid-item"></div>
                <div class="turtle-grid-item"></div>
                <div class="turtle-grid-item"></div>
                <div class="turtle-grid-item"></div>
                <div class="turtle-grid-item"></div>
                <div class="turtle-grid-item"></div>
                <div class="turtle-grid-item"></div>
                <div class="turtle-grid-item"></div>
                <div class="turtle-grid-item"></div>
            </div>

            <!-- 连线特效 Canvas -->
            <canvas id="special-effects"></canvas>

            <!-- 文字特效 Css -->

            <div class="text-effects">
                <div class="text-effects-title">三连位</div>
                <div class="text-effects-subtitle">加赠3只</div>
            </div>
        </div>

        <!-- 信心面板 -->
        <div class="info-panel">
            <div class="form">
                <!-- 选择颜色 -->
                <div class="form-item">
                    <div class="form-item__label">幸运色</div>
                    <div class="form-item__value">
                        <select id="selectLuckyColor">
                            <option value="red">红色</option>
                            <option value="yellow">黄色</option>
                            <option value="purple">紫色</option>
                            <option value="orange">橙色</option>
                            <option value="green">绿色</option>
                            <option value="cyan">青色</option>
                            <option value="pink">粉色</option>
                            <option value="blue">蓝色</option>
                            <option value="brown">咖色</option>
                            <option value="rose">玫红色‌</option>
                        </select>
                    </div>
                </div>
                <div class="form-item">
                    <div class="form-item__label">数量</div>
                    <div class="form-item__value">
                        <select id="selectBuyCount">
                            <option value="10">10包</option>
                            <option value="20">20包</option>
                            <option value="30">30包</option>
                            <option value="40">40包</option>
                            <option value="50">50包</option>
                        </select>
                    </div>
                </div>
                <div class="start-btn">开始</div>
            </div>

            <div class="history"></div>
        </div>
    </div>

    <script type="module">

        import { Randoms } from "https://gcore.jsdelivr.net/npm/@3r/tool/lib/randoms.js";

        /**
         * 等待时间
         * @author 	 linyisonger
         * @date 	 2025-01-22
         */
        function waitTime(time) {
            return {
                then: function (resolve) {
                    setTimeout(resolve, time)
                }
            }
        }

        /**
         * 初始化平面数组
         * @author 	 linyisonger
         * @date 	 2025-01-13
         * 
         * @template T
         * @param {number} rows
         * @param {number} cols
         * @param {T|(x,y)=>T} init 
         * 
         * @return {T[][]}
         */
        function createFlatArray(rows, cols, init = 0) {
            let level1 = []
            for (let y = 0; y < cols; y++) {
                let level2 = [];
                for (let x = 0; x < rows; x++) {
                    level2[x] = typeof init == "function" ? init(x, y) : init;
                }
                level1[y] = level2
            }
            return level1
        }

        // 红色、黄色、紫色、橙色、绿色、青色、粉色、蓝色、咖色和玫红色‌
        const TURTLE_COLOR = {
            NONE: '',
            RED: 'red',
            YELLOW: 'yellow',
            PURPLE: 'purple',
            ORANGE: 'orange',
            GREEN: 'green',
            CYAN: 'cyan',
            PINK: 'pink',
            BLUE: 'blue',
            BROWN: 'brown',
            ROSE: "rose"
        }


        const TURTLE_COLOR_ZH = {
            red: '红色',
            yellow: '黄色',
            purple: '紫色',
            orange: '橙色',
            green: '绿色',
            cyan: '青色',
            pink: '粉色',
            blue: '蓝色',
            brown: '咖色',
            rose: '玫红色‌',
        }


        class Turtle {
            x = 0;
            y = 0;
            color = TURTLE_COLOR.NONE;
            constructor(x, y) {
                this.x = x;
                this.y = y;
            }

            clear() {
                turtlesDom.item(this.x + this.y * 3).innerHTML = ''
            }
        }

        const assetConfig = {
            'red': './assets/turtle/red.png',
            'yellow': './assets/turtle/yellow.png',
            'purple': './assets/turtle/purple.png',
            'orange': './assets/turtle/orange.png',
            'green': './assets/turtle/green.png',
            'cyan': './assets/turtle/cyan.png',
            'pink': './assets/turtle/pink.png',
            'blue': './assets/turtle/blue.png',
            'brown': './assets/turtle/brown.png',
            "rose": './assets/turtle/rose.png',
        }


        let map = createFlatArray(3, 3, (x, y) => new Turtle(x, y)) // 地图
        let colors = Object.keys(assetConfig) // 颜色
        let turtles = map.flat(2) // 所有乌龟
        let turtlesDom = document.querySelectorAll('.turtle-grid-item') // 九宫格
        let luckyColor = colors[1]; // 幸运色
        let buyCount = 10;  // 购买数量
        let totalCount = buyCount; // 总数量
        let unpackCount = 0; // 拆开数量
        let turtleCount = {} // 不同颜色的乌龟数量
        let history = []
        /**
         * 相同的
         * @author 	 linyisonger
         * @date 	 2025-01-16
         */
        function same(self, target) {
            return map[self.y][self.x].color == map[target.y][target.x].color && map[self.y][self.x].color != TURTLE_COLOR.NONE;
        }

        /**
         * 二联判断
         * @author 	 linyisonger
         * @date 	 2025-01-16
         */
        async function isTwin() {
            // 循环
            for (let i = 0; i < turtles.length - 1; i++) {
                const cur = turtles[i];
                if (cur.color === TURTLE_COLOR.NONE) continue;
                for (let j = i + 1; j < turtles.length; j++) {
                    const nex = turtles[j]
                    if (same(cur, nex)) {
                        await eliminate([cur, nex])
                        await isTwin()
                    }
                }
            }
        }

        /**
         * 三连判断
         * @author 	 linyisonger
         * @date 	 2025-01-16
         */
        async function isTriplet() {
            // let sameList = []
            // 横向
            for (let i = 0; i < 3; i++) {
                let sameArray = isSameMatch({ x: 0, y: i }, { x: 1, y: 0 })
                sameArray.length && await eliminate(sameArray) // sameList.push(sameArray)
            }
            // 纵向
            for (let i = 0; i < 3; i++) {
                let sameArray = isSameMatch({ x: i, y: 0 }, { x: 0, y: 1 })
                sameArray.length && await eliminate(sameArray) // sameList.push(sameArray)
            }
            // 对角线 - 左上 右下
            {
                let sameArray = isSameMatch({ x: 0, y: 0 }, { x: 1, y: 1 })
                sameArray.length && await eliminate(sameArray) // sameList.push(sameArray)
            }
            // 对角线 - 右上 左下
            {
                let sameArray = isSameMatch({ x: 2, y: 0 }, { x: -1, y: 1 })
                sameArray.length && await eliminate(sameArray) // sameList.push(sameArray)
            }
            // return sameList;
        }


        /**
         * 清台
         * @author 	 linyisonger
         * @date 	 2025-01-23
         */
        async function isCleanUp() {
            let isClean = turtles.every(t => t.color === TURTLE_COLOR.NONE)
            if (isClean) await eliminate([])
        }


        /**
         * 幸运色
         * @author 	 linyisonger
         * @date 	 2025-01-23
         * 
         * @param {Turtle} turtle
         */
        async function isLuckyColor(turtle) {
            if (turtle.color === luckyColor) {
                specialEffects([turtle])
                textEffects([turtle])
                await waitTime(3000);
            }
        }


        /**
         * 是否相同位置匹配
         * @author 	 linyisonger
         * @date 	 2025-01-16
         */
        function isSameMatch(start, direction, count = 2) {
            let sameArray = [start]
            for (let i = 0; i < count; i++) {
                let last = sameArray[sameArray.length - 1]
                let target = { x: last.x + direction.x, y: last.y + direction.y }
                if (!same(last, target)) return []
                sameArray.push(target)
            }
            return sameArray;
        }



        /**
         * 拆盲盒
         * @author 	 linyisonger
         * @date 	 2025-01-16
         */
        async function unpack() {
            // 颜色
            let color = colors[Randoms.int(0, colors.length)]
            // 第一
            let turtleIndex = turtles.findIndex(t => t.color == TURTLE_COLOR.NONE);
            // 摆放
            if (turtleIndex > -1 && totalCount != unpackCount) {
                turtles[turtleIndex].color = color;
                // 新建IMG
                let imgDom = document.createElement('img')
                imgDom.src = assetConfig[color]
                turtlesDom.item(turtleIndex).appendChild(imgDom)
                await isLuckyColor(turtles[turtleIndex])
                unpackCount++;
                turtleCount[color] = (turtleCount[color] || 0) + 1
                await unpack();
            }
            // 结算
            else {
                await waitTime(1000);

                console.log('结算');
                // 三联
                await isTriplet();
                // 二联
                await isTwin();
                // 清台 
                await isCleanUp()

                // 结束
                if (totalCount == unpackCount) {
                    turtles.forEach((t) => {
                        t.color = TURTLE_COLOR.NONE
                        t.clear()
                    })
                    addHistory()
                }
                else {
                    await unpack();
                }
            }

        }


        /**
         * 消除
         * @author 	 linyisonger
         * @date 	 2025-01-22
         * 
         * @param {Turtle[]} link
         */
        async function eliminate(link) {
            link.forEach(item => map[item.y][item.x].color = TURTLE_COLOR.NONE)
            specialEffects(link)
            textEffects(link)
            await waitTime(3000);
        }

        /**
         * 特效
         * @author 	 linyisonger
         * @date 	 2025-01-22
         * 
         * @param {Turtle[]} link
         */
        function specialEffects(link) {
            if (!link.length) return;
            /** @type {HTMLCanvasElement} */
            let canvas = document.querySelector("#special-effects")
            let ctx = canvas.getContext('2d')
            let width = canvas.clientWidth;
            let height = canvas.clientHeight;
            canvas.width = width;
            canvas.height = height;
            let gw = width / 3;
            let gh = height / 3;
            let lw = 4;
            ctx.clearRect(0, 0, width, height)
            ctx.strokeStyle = '#ff2222'
            ctx.lineWidth = lw;
            for (let i = 0; i < link.length; i++) {
                const item = link[i];
                ctx.rect(item.x * gw + lw / 2, item.y * gh + lw / 2, gw - lw, gh - lw)
            }
            ctx.stroke()

            setTimeout(() => {
                if (link.length > 1) link.forEach(item => map[item.y][item.x].clear())
                ctx.clearRect(0, 0, width, height)
            }, 1500);
        }


        /**
        * 文字特效
        * @author 	 linyisonger
        * @date 	 2025-01-22
        * 
        * @param {Turtle[]} link
        */
        function textEffects(link) {
            let dom = document.querySelector('.text-effects');
            let titleDom = dom.querySelector('.text-effects-title')
            let subtitleDom = dom.querySelector('.text-effects-subtitle')

            // 对对碰：2个同色格，一起拿走，加赠1只； ✔
            // 三连：同一直线上（横、竖、对角线）3个同色格，一起拿走，加赠3只； ✔
            // 清台: +5
            if (link.length === 3) {
                titleDom.textContent = '三连位'
                subtitleDom.textContent = '加赠3只'
                totalCount += 3;
            }
            else if (link.length === 2) {
                titleDom.textContent = '对对碰'
                subtitleDom.textContent = '加赠1只'
                totalCount += 1;
            }
            else if (link.length === 0) {
                titleDom.textContent = '清台'
                subtitleDom.textContent = '加赠5只'
                totalCount += 5;
            }
            else if (link.length === 1) {
                titleDom.textContent = '幸运色'
                subtitleDom.textContent = '加赠1只'
                totalCount += 1;
            }
            dom.classList.add('show')

            setTimeout(() => {
                dom.classList.remove('show')
            }, 1500)
        }



        /**
         * 追加历史记录
         * @author 	 linyisonger
         * @date 	 2025-01-24
         */
        function addHistory() {
            let his = {
                num: history.length + 1,
                luckyColor,
                buyCount,
                totalCount,
                turtleCount,
            }
            history.push(his)
            let historyDom = document.querySelector('.info-panel .history')

            let turtleItemStr = ``;

            for (const key in turtleCount) {
                turtleItemStr += `
                    <div class="turtle-item">
                        <img src="./assets/turtle/${key}.png"> × ${turtleCount[key]}
                    </div> 
                `
            }



            historyDom.innerHTML += `
                <div class="history-item">
                    <div class="base-info">
                        <div class="num">第${his.num}次</div>
                        <div class="color">幸运色: ${TURTLE_COLOR_ZH[his.luckyColor]}</div>
                        <div class="buy">购买数量: ${his.buyCount}</div>
                        <div class="get">获取数量: ${his.totalCount}</div>
                    </div>
                    <div class="turtle-info">
                        ${turtleItemStr}
                    </div>
                </div>
            `
        }

        document.querySelector('.start-btn').addEventListener("click", () => {
            luckyColor = document.querySelector('#selectLuckyColor').value
            buyCount = +document.querySelector('#selectBuyCount').value
            totalCount = buyCount;
            unpackCount = 0;
            unpack()
        })


    </script>


</body>

</html>